/*
 * jQuery.appear
 * https://github.com/bas2k/jquery.appear/
 * http://code.google.com/p/jquery-appear/
 * http://bas2k.ru/
 *
 * Copyright (c) 2009 Michael Hixson
 * Copyright (c) 2012-2014 Alexander Brovikov
 * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
 */
;(function ($) {
    "use strict";

    $(document).ready(function() {

        $.fn.appear = function(fn, options) {

            var settings = $.extend({

                //arbitrary data to pass to fn
                data: undefined,

                //call fn only on the first appear?
                one: true,

                // X & Y accuracy
                accX: 0,
                accY: 0

            }, options);

            return this.each(function() {

                var t = $(this);

                //whether the element is currently visible
                t.appeared = false;

                if (!fn) {

                    //trigger the custom event
                    t.trigger('appear', settings.data);
                    return;
                }

                var w = $(window);

                //fires the appear event when appropriate
                var check = function() {

                    //is the element hidden?
                    if (!t.is(':visible')) {

                        //it became hidden
                        t.appeared = false;
                        return;
                    }

                    //is the element inside the visible window?
                    var a = w.scrollLeft();
                    var b = w.scrollTop();
                    var o = t.offset();
                    var x = o.left;
                    var y = o.top;

                    var ax = settings.accX;
                    var ay = settings.accY;
                    var th = t.height();
                    var wh = w.height();
                    var tw = t.width();
                    var ww = w.width();

                    if (y + th + ay >= b &&
                        y <= b + wh + ay &&
                        x + tw + ax >= a &&
                        x <= a + ww + ax) {

                        //trigger the custom event
                        if (!t.appeared) t.trigger('appear', settings.data);

                    } else {

                        //it scrolled out of view
                        t.appeared = false;
                    }
                };

                //create a modified fn with some additional logic
                var modifiedFn = function() {

                    //mark the element as visible
                    t.appeared = true;

                    //is this supposed to happen only once?
                    if (settings.one) {

                        //remove the check
                        w.unbind('scroll', check);
                        var i = $.inArray(check, $.fn.appear.checks);
                        if (i >= 0) $.fn.appear.checks.splice(i, 1);
                    }

                    //trigger the original fn
                    fn.apply(this, arguments);
                };

                //bind the modified fn to the element
                if (settings.one) t.one('appear', settings.data, modifiedFn);
                else t.bind('appear', settings.data, modifiedFn);

                //check whenever the window scrolls
                w.scroll(check);

                //check whenever the dom changes
                $.fn.appear.checks.push(check);

                //check now
                (check)();
            });
        };

        //keep a queue of appearance checks
        $.extend($.fn.appear, {

            checks: [],
            timeout: null,

            //process the queue
            checkAll: function() {
                var length = $.fn.appear.checks.length;
                if (length > 0) while (length--) ($.fn.appear.checks[length])();
            },

            //check the queue asynchronously
            run: function() {
                if ($.fn.appear.timeout) clearTimeout($.fn.appear.timeout);
                $.fn.appear.timeout = setTimeout($.fn.appear.checkAll, 20);
            }
        });

        //run checks when these methods are called
        $.each(['append', 'prepend', 'after', 'before', 'attr',
            'removeAttr', 'addClass', 'removeClass', 'toggleClass',
            'remove', 'css', 'show', 'hide'], function(i, n) {
            var old = $.fn[n];
            if (old) {
                $.fn[n] = function() {
                    var r = old.apply(this, arguments);
                    $.fn.appear.run();
                    return r;
                }
            }
        });
    });
})(jQuery);